using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ReactiveLang
{
    using Util;

    [TestClass]
    public class ExceptionHandlingTests: ReactiveLangTestClassBase
    {
        IStatement<Unit> AssignmentWithException()
        {
            var state = new Variable<int>();
            var value = Expression.CreateWithDisposable<int>(o =>
            {
                o.OnException(new Exception());
                return Disposable.Empty;
            });

            return Assign(state, value);
        }

        [TestMethod]
        [ExpectedException(typeof(ReactiveCodeException))]
        public void ExceptionInAssignment()
        {
            var handle = Host.Add(AssignmentWithException(), false);

            bool exceptionInHost = false;
            bool exceptionInHandle = false;

            Host.UnhandledException += (s, e) =>
            {
                Assert.IsFalse(e.IsHandled);
                exceptionInHost = true;
            };
            handle.UnhandledException += (s, e) =>
            {
                Assert.IsFalse(e.IsHandled);
                Assert.IsFalse(exceptionInHost);
                exceptionInHandle = true;
            };

            try
            {
                handle.Enabled = true;
                Assert.Fail();
            }
            catch (ReactiveCodeException)
            {
                Assert.IsTrue(exceptionInHost && exceptionInHandle);
                throw;
            }
            catch (Exception)
            {
                Assert.Fail();
            }
        }

        [TestMethod]
        public void HandledExceptionInAssignment()
        {
            var handle = Host.Add(AssignmentWithException(), false);

            bool handledException = false;
            handle.UnhandledException += (s, e) =>
            {
                e.SetHandled();
                handledException = true;
            };

            handle.Enabled = true;
            Assert.IsTrue(handledException);
        }
    }
}